/* =======================封装的js========================= */
// forEach强制跳出循环
throw Error();

// 解决uniapp textarea层级过高问题
// v-show
// 获取浏览器携带的参数
// (1)浏览器只带一个参数的时候
// let url = window.location.href; 
let url = 'http://check-report.sdhuan.cn?code=d576d1a84493152d8bfe828c0f20b505';
let temp = url.split('=');
let pram = temp[1];
console.log(pram);

// (2)浏览器带多个参数的时候
// let url = window.location.href; 
let url = 'http://check-report.sdhuan.cn?code=d576d1a84493152d8bfe828c0f20b505&state=STATE';
let temp2 = url.split('?')[1];
let urlArr = temp2.split('&');
let urlList = {};
urlArr.forEach(item => {
	let urls = item.split('=');
	urlList[urls[0]] = urls[1];
})
console.log(urlList);


// vue props 简易写法和规整写法
Vue.component('my-component', {
	props: ['xxx'],
	props: {
		//必须是数字类型
		propA: Number
		//必须是字符串或数字类型
		propB: [String, number]
		//布尔值,如果没有定义，默认值是true
		propC: {
			type: Boolean,
			default: true
		},
		//数字，而且是必传
		propD: {
			type: Number,
			required: true
		},
		//如果是数组或对象，默认值必须是一个函数来返回
		propE: {
			type: Array,
			default: function() {
				return [];
			}
		},
		//自定义一个验证函数
		propF: {
			validator: function(value) {
				return value > 10
			}
		}
	}
});
// 数字数组转化为字符串数组
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); //结果： ['1', '2', '3', '4', '5', '6', '7', '8', '9']

// 字符串数组转化为数字数组
var a = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
a.map(Number); //结果：[1, 2, 3, 4, 5, 6, 7, 8, 9]

// js查询是否包含某个字符
var arr = [1, 2, 3];
console.log(arr.indexOf(1)); // 返回0
console.log(arr.indexOf(5)); // 返回-1

var arr_qf = ["jpg", "png", "gif", "bmp", "html", "jpeg"];
arr_qf.contains('html’') // js的contains方法用来查看dom元素的包含关系，

// 同indexOf一样，includes仅能用于数组操作
array('a', 'b').includes('a') // 返回值为true 
array('a', 'b').includes('') // 返回值为false

if ([{ name: 'trent' }, { name: 'jason' }].includes({ name: 'trent' })) {}


// js模糊查询， 对你数组对象中某个属性值是否包含特定值
let dat = [];
items.map(res => {
	// console.log('总数居的值---', res.recordUser)
	// console.log('要搜索的值----', params.recordUser)
	// console.log('匹配的值----', res.recordUser.search(params.recordUser))
	if (res.xx.search(this.xx) != -1) {
		dat.push(res);
	} else {
		dat.push();
	}
});
that.data = dat;

// js判断对象是否为空
Object.keys(item.device).length !== 0

// js数字截取小数点后俩位
Number.toFixed(2)

// js字符串截取小数点后俩位
let s = 22.127456 + "";
let str = s.substring(0, s.indexOf(".") + 3);

//  js字符串截取除了后三位所有的数据
let s = 22.127456 + "";
let str = s.substr(0, s.length - 3);

// js删除数组对象的某一个对象
data.forEach((res, index) => {
	if (res.xx == xx) {
		console.log('满足条件的数据----', res)
		console.log('满足条件的数据的index', index)
		data.splice(index, 1)
	}
});
// js数组的每一项添加一个元素
// 方法一
res.forEach(item => {
	this.$set(item, '参数名', 参数值)
})

// 方法二
let dat = []
res.forEach(item => {
	dat.push(Object.assign(item, {
		'参数名': 参数值
	}))
})

// js数组删除数组对象中的某条属性, 删除id
let dat1 = []
data.forEach(res => {
	// 方法1
	delete res.id;
	// 方法2
	let { id, ...params } = res
	dat1.push(...params)
})

// js 新增对象的某一项
this.$set(row, 'constructionName', this.personelId)
// 新增多个属性
this.obj = Object.assign({}, this.obj, { a: 1, e: 2 })

// js 删除对象某一项
var dat = {
	name: '王坤',
	age: 18,
	build: 183
}
delete dat.build

// 字符串转数组
e.split(',')
// 数组转字符串
e.toString()

// vue data 初始化数据
Object.assign(this.$data.footData, this.$options.data().footData); // 初始化 data 中的 footData 数据
Object.assign(this.$data, this.$options.data()); // 初始化全部的 data数据

// vue清空提交得表单
this.$refs.XX.resetFields()
	// vue表单提交后清空图片上传的数据
	<
	upload ref = "xx" > < /upload>
this.$refs.XX.clearFiles()


// 增强用户体验，准确定位问题，完善的前端处理方案，比如前端监控系统 try catch(但是也有性能问题)
try {
	// tryCode - 尝试执行代码块
} catch (err) {
	// catchCode - 捕获错误的代码块
} finally {
	// finallyCode - 无论 try / catch 结果如何都会执行的代码块
}

// input框 只能输入数字，并且大于等于0的正数，允许小数 
<
input type = "number"
step = "1"
min = "0"
onkeyup = "this.value= this.value.match(/\d+(\.\d{0,2})?/) ? this.value.match(/\d+(\.\d{0,2})?/)[0] : ''" >
	// 大于0的正整数
	<
	input type = "text"
placeholder = "输入金额"
style = "width: 80px;"
value = ""
onkeyup =
	"if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'')}else{this.value=this.value.replace(/\D/g,'')}"
onafterpaste =
	"if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'')}else{this.value=this.value.replace(/\D/g,'')}" /
	>
	// input框 只能输入大于0数字
	onkeyup = "this.value=this.value.replace(/\D|^0/g,'')"
onafterpaste = "this.value=this.value.replace(/\D|^0/g,'')"

const e = require('express');



// 判断页面在 微信 / 微博 / QQ / 支付宝 / 钉钉 内置浏览器内打开
const u = navigator.userAgent.toLowerCase()
let isApp =
	u.match(/MicroMessenger/i) == 'micromessenger' ||
	u.match(/WeiBo/i) == 'weibo' ||
	(u.indexOf('qq') !== -1 && u.indexOf('mqqbrowser') === -1) ||
	/alipay/gi.test(u) ||
	u.indexOf('dingtalk') !== -1
if (isApp) {
	// 在内置浏览器里打开
} else {
	window.open = ''
	window.location.href = ''
	let src = data.appDownloadUrl
	let iframe = document.createElement('iframe')
	iframe.style.display = 'none'
	iframe.src =
		'javascript: \'<script>location.href="' + src + '"</script>\''
	document.getElementsByTagName('body')[0].appendChild(iframe)
}


// base64转换为图片
base64ImgtoFile(dataurl, filename = 'file') {
		let arr = dataurl.split(',');
		let mime = arr[0].match(/:(.*?);/)[1];
		let suffix = mime.split('/')[1];
		let bstr = atob(arr[1]);
		let n = bstr.length;
		let u8arr = new Uint8Array(n);
		while (n--) {
			u8arr[n] = bstr.charCodeAt(n);
		}
		return new File([u8arr], `${filename}.${suffix}`, {
			type: mime,
		});
	},

	// 排序
	var num = [7, 8, 6, 5, 2]
//倒序排列
num.sort((a, b) => {
	return b - a
})
//正序排列
num.sort((a, b) => {
	return a - b
})
// 只循环满足条件得数据
data.sort((a, b) => {
	let x = 'nums';
	console.log(a[x])
	if (a[x] == null || b[x] == null) {
		return;
	} else {
		return a[x] - b[x];
	}
	return;
});
// 根据特殊字符截取字符串
let res = 'http://baidu.com/78135211268.png'
res.substring(res.lastIndexOf('\/') + 1, res.length - 4); // 截取
// 得到: 78135211268


// 时分秒倒计时
countTime() {
		// 获取当前时间
		let date = new Date()
		let now = date.getTime()
		// 设置截止时间
		let endDate = new Date(this.curStartTime) // this.curStartTime需要倒计时的日期
		let end = endDate.getTime()
		// 时间差
		let leftTime = end - now
		// 定义变量 d,h,m,s保存倒计时的时间
		if (leftTime >= 0) {
			// 天
			this.day = Math.floor(leftTime / 1000 / 60 / 60 / 24)
			// 时
			let h = Math.floor((leftTime / 1000 / 60 / 60) % 24)
			this.hour = h < 10 ? '0' + h : h
			// 分
			let m = Math.floor((leftTime / 1000 / 60) % 60)
			this.min = m < 10 ? '0' + m : m
			// 秒
			let s = Math.floor((leftTime / 1000) % 60)
			this.second = s < 10 ? '0' + s : s
		} else {
			this.day = 0
			this.hour = '00'
			this.min = '00'
			this.second = '00'
		}
		// 等于0的时候不调用
		if (Number(this.hour) === 0 && Number(this.day) === 0 && Number(this.min) === 0 && Number(this.second) === 0) {
			return false
		} else {
			// 递归每秒调用countTime方法，显示动态时间效果,
			setTimeout(this.countTime, 1000)
		}
	},


	// 时间格式转换 2021-02-21 21:12:12 转换成 2121/02/21 21:12:12
	let times = 2021 - 02 - 21 21: 12: 12
times.replace(/-/g, '/')

// 字符串装日期格式化
let date = '20210320'
year = String(date).substr(0, 4)
month = String(date).substr(4, 6)
day = String(date).substr(6, 8)
date = year + '-' + month + '-' + day



// js清空特殊字符
value.replace(/[`~!@#$%^&*()_\-+=<>?:"{ }|,.\/;'\\[\]·~！@#￥%……&*（）——\-+={ }|《》？：""【】、；‘'，。、]/g, "");
// 只能输入汉字、英文、数字
value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g, "");
// 只可输入数字 
value.replace(/[^\d]/g, "");

// excel表格的导出
// 请求接口要写：responseType: 'blob', // 类型看后台传甚么

let disposition = res.headers['content-disposition'];
let fileName = decodeURI(
	disposition.split('filename=')[1].split(';filename*=')[0]
);
let blob = new Blob([res.data], { type: 'application/.xls' }); //.xls是我和后台约定好的文件格式
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
link.remove();


// 文件预览
downFile(item) {
  let url = "https://view.officeapps.live.com/op/view.aspx?src=" + item.fileUrl;
  const width = 1000;
  const height = 800;
  const top = (window.screen.availHeight - height) / 2;
  const left = (window.screen.availWidth - width) / 2;
  window.open(
    url,
    "",
    "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left
  );
},

// zip 文件流下载
downAll(dataList).then(res => {
	console.log('整体导出请求结果', res)
	// zip文件流下载
	const content = res.data
	const blob = new Blob([content], {
		type: "application/zip"
	})
	// var timestamp = (new Date()).valueOf();
	// const fileName = timestamp + '.zip'
	// 前端下载文件流并且获取heads中的filename文件名且解决中文乱码的方法
	let temp = res.headers["content-disposition"].split(";")[1].split("=")[1];
	//对文件名乱码转义--【Node.js】使用iconv-lite解决中文乱码
	let iconv = require('iconv-lite');
	iconv.skipDecodeWarning = true; //忽略警告
	let fileName = iconv.decode(temp, 'UTF-8');
	fileName = fileName.substring(1, fileName.length - 1)

	if ('download' in document.createElement('a')) { // 非IE下载
		const elink = document.createElement('a')
		elink.download = fileName
		elink.style.display = 'none'
		elink.href = window.URL.createObjectURL(blob)
		document.body.appendChild(elink)
		elink.click()
		window.URL.revokeObjectURL(elink.href) // 释放URL 对象
		document.body.removeChild(elink)
	} else { // IE10+下载
		navigator.msSaveBlob(blob, fileName)
	}
})

// 在线打开word文档
window.open('https://view.officeapps.live.com/op/view.aspx?src=' + 地址) // 在线打开word文档
// 在线下载word文档 
window.open(地址)

// 在线下载pdf
fileClick(row, fileName) {
	let url = window.URL.createObjectURL(new Blob([row]));
	let link = document.createElement('a');
	link.style.display = 'none';
	link.href = url;
	link.setAttribute('download', fileName);
	document.body.appendChild(link);
	link.click();
}

// 在线打开pdf
window.open(地址) // 在线下载word文档
// 在线下载pdf
// 下载检测报告
// <el-button type="primary"  @click="rowTesting(row, row.engineeringName +'_'+ row.jobNumber + '检测报告'+ '.pdf')">检测报告</el-button>
rowTesting(row, filename) {
	let that = this
	that.getBlob(row.report.attachUrl, // 地址
		function(blob) {
			that.saveAs(blob, filename);
		})
}
getBlob(url, cb) {
	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.responseType = 'blob';
	xhr.onload = function() {
		if (xhr.status === 200) {
			cb(xhr.response);
		}
	};
	xhr.send();
}
saveAs(blob, filename) {
	if (window.navigator.msSaveOrOpenBlob) {
		navigator.msSaveBlob(blob, filename);
	} else {
		var link = document.createElement('a');
		var body = document.querySelector('body');

		link.href = window.URL.createObjectURL(blob);
		link.download = filename;

		// fix Firefox
		link.style.display = 'none';
		body.appendChild(link);
		link.click();
		body.removeChild(link);
		window.URL.revokeObjectURL(link.href);
	}
}


// vue input框限制只能输入数字并且小数点保留俩位
///input只允许输入整数和小数（小数只保留小数点后两位）

//onkeyup： 键盘按键抬起时  onafterpaste： 黏贴后
onkeyup = "this.value=this.value.match(/\d+\.?\d{0, 2}/)"
onafterpaste = "this.value=this.value.match(/\d+\.?\d{0, 2}/)"

//// input只允许输入整数
onkeyup = "this.value=this.value.replace(/\D/g,'')"
onafterpaste = "this.value=this.value.replace(/\D/g,'')"

// 身份证中间四位****
let vcard = '371083199411181236'
let cc = vcard.replace(/^(.{7})(?:\d+)(.{7})$/, "$1****$2");

// javascript:void(0)：被称为死链接点击不会有任何效果
// <a href="javascript:void(0)" ></a>
/* ================================================ */
// 文件下载的方式
// （1）利用Html5的download属性进行下载， 针对后端的get请求
<
a href = "test.txt"
download = "test1.txt" > 下载 < /a>

// (2) ajax后端请求  post方式
let getInfo = function(url, param, type, blob) {
	const promise = new Promise(function(resolve, reject) {
		$.ajax({
			type: type,
			url: url,
			data: param,
			dataType: 'json',
			responseType: blob,
			success(res) {
				resolve(res)
			},
			error(res) {
				reject('响应错误')
			}
		})
	})
	return promise
}

let result = []
getInfo('http://xxx', {
	channelIds: 1
}, 'GET', 'blob').then(res => {
	console.log(res)
})

// 然后将返回的数据传给downLoadXls方法里，第二个形参是文件名称，然后系统就开始自动下载了~
function downLoadXls(data, filename) { // 地址和文件名字
	//var blob = new Blob([data], {type: 'application/vnd.ms-excel'})接收的是blob，若接收的是文件流，需要转化一下
	if (typeof window.chrome !== 'undefined') {
		// Chrome version
		var link = document.createElement('a');
		link.href = window.URL.createObjectURL(data);
		link.download = filename;
		link.click();
	} else if (typeof window.navigator.msSaveBlob !== 'undefined') {
		// IE version
		var blob = new Blob([data], {
			type: 'application/force-download'
		});
		window.navigator.msSaveBlob(blob, filename);
	} else {
		// Firefox version
		var file = new File([data], filename, {
			type: 'application/force-download'
		});
		window.open(URL.createObjectURL(file));
	}
}
// URL.createObjectURL() 静态方法会创建一个 DOMString，一个DOMString包含了一个对象URL，该URL可用于指定源 object的内容。





/* 登录页面的背景图在安卓手机上会被弹起的键盘顶上去 */
$('body').height($('body')[0].clientHeight)

/* ================================================ */

/* 有时候一些按钮的简单点击交互可以通过css伪类来实现；必须点击了更改颜色；松开恢复；
IOS手机会出现伪类无效的情况；iOS系统的移动设备中，
需要在按钮元素或body/html上绑定一个touchstart事件才能激活:active状态。 */
// 移动端页面实现PC端页面鼠标移入效果

document.body.addEventListener('touchstart', function() {
	//...空函数即可
})

/* ================================================ */

/* 遮罩层下不可滑动 */

// （1）打开遮罩层的时候，给遮罩层下面的div添加fixed，页面就是固定的，没办法滑动了。（推荐）


/* ================================================ */

// vue移动端出现遮罩层时在遮罩层滑动时禁止遮罩层下方页面滑动

// 解决方法:
// (1)在遮罩层标签上添加@touchmove.prevent
// (2)把遮罩层显示时把下方的父盒子css设置为固定定位宽100%高100%超出隐藏 两种方法都行


/* ================================================ */
/* input实时监听获取内容

<input type="text" />
    $('input').on('input propertychange', function () { // propertychange能够捕获每次输入值的变化。
      console.log($(this).val());
});
    */
/* ================================================ */
// JS判断移动端还是PC端并显示不同的网址

function browserRedirect() {
	var sUserAgent = navigator.userAgent.toLowerCase();
	var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
	var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
	var bIsMidp = sUserAgent.match(/midp/i) == "midp";
	var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
	var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
	var bIsAndroid = sUserAgent.match(/android/i) == "android";
	var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
	var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
	if (!(bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM)) {
		window.location.href = "http://blog.csdn.net/bysjlwdx";
	} else {
		window.location.href = "http://m.blog.csdn.net/blog/index?username=bysjlwdx";
	}
}
browserRedirect();

/* ================================================ */

/* 手机号限制11位 */

<
input type = "text"
oninput = "if(value.length>11)value=value.slice(0,11)" / >

	/* ================================================ */

	/* JQ + promise + ajax封装方法 */

	// （1） ajax方法嵌套执行
	function check(url, param, type) {
		const promise = new Promise(function(resolve, reject) {
			$.ajax({
				type: type,
				url: url,
				data: param,
				dataType: 'json',
				success(res) {
					resolve(res)
				},
				error(res) {
					reject('响应错误')
				}
			})
		})
		return promise
	}

let p1 = check("blog.json", {
	IJ: 1
}, 'GET')
let p2 = check("blog.json", {
	IJ: 1
}, 'GET')
let p3 = check("blog.json", {
	IJ: 1
}, 'GET')

// 嵌套执行方法 想让p1完成后再执行p2再执行p3,有一处错误就不会往下执行
// Promise写法
p1.then(res => {
	console.log(res)
	return p2
}).then(res => {
	console.log(res)
	return p3
}).then(res => {
	console.log(res)
})

//想让p1完成后再执行p2再执行p3
//能避免回调
// async/await写法
async function asy() {
	await p1.then((res) => {
		console.log(res)
	});
	await p2.then((res) => {
		console.log(res)
	});;
	await p3.then((res) => {
		console.log(res)
	});;
}
asy();

// async/await循环获取数据(串行)之for循环
var arr = [1, 2, 3, 4, 5]
	(async () => {
		for (var i = 0; i < arr.length; i++) {
			result = await arr[i];
			console.log(result);
		}
	})()

// async/await for循环里使用"
promiseList.forEach(async (item) => {
	console.log('输出结果:', await item)
});



// 同时执行三个方法 在表单提交的各种验证
Promise.all([p1, p2, p3]).then(res => {
	console.log(res)
})




// (2)jq中使用promise封装ajax
let getInfo = function(url, param, type) {
	const promise = new Promise(function(resolve, reject) {
		$.ajax({
			type: type,
			url: url,
			data: param,
			dataType: 'json',
			success(res) {
				resolve(res)
			},
			error(res) {
				reject('响应错误')
			}
		})
	})
	return promise
}

let result = []
getInfo('http://xxx', {
	channelIds: 1
}, 'GET').then(res => {
	console.log(res)
	$.each(res, function(ket, val) {
		result += "<label>姓名：" + val.name + "</label><br/>"
	});
	$("#div1").push(result);
})

/* async/awiat + axios封装方法 */
// async/awiat和try/catch（检查代码语句）连合使用
async getInfo() {
	try {
		const data = await axios.get('home', parmas: {
			inde: 0
		})
		console.log(data)
	} catch (err) {
		console.log(err)
	}
}
this.getInfo()

// async/awiat和try/catch（检查代码语句）连合使用
async getInfo() {
	try {
		// 按顺序执行
		const data = await axios.get('home1', parmas: {
			inde: 0
		})
		const data = await axios.get('home2', parmas: {
			inde: 0
		})
		const data = await axios.get('home3', parmas: {
			inde: 0
		})
		console.log(data)
	} catch (err) {
		console.log(err)
	}
}
this.getInfo()

// 封装async/awiat + axios  + promise 封装
methods: {
	getHistoryData(url, data) {
		return new Promise((resolve, reject) => {
				axios.get('url, {params: data})
					.then((res) => {
						resolve(res)
					}).catch((err) => {
						reject(err)
					})
				})
		}
	}

	async created() {
		try {
			let res = await this.getHistoryData(url, data)
			console.log(res)
		} catch (err) {
			console.log(err)
			alert('请求出错')
		}
	}

	// axios.all() axios.spread()解决并发请求
	methods: {
		getAllTask() {
			console.log('调用第一个接口')
			return this.axios.get('home', params: {
				offset: 1,
				pageSize: 10
			})
		},
		getAllCity() {
			console.log('调用第二个接口')
			return this.axios.get('home/list', params: {
				offset: 1,
				pageSize: 10
			})
		}
	},

	//在mounted周期同时发送两个请求，并在请求都结束后，输出结果
	mounted() {
		var that = this;
		this.axios.all([that.getAllTask(), that.getAllCity()])
			.then(that.axios.spread(function(allTask, allCity) {
				console.log('所有请求完成')
				console.log('请求1结果', allTask)
				console.log('请求2结果', allCity)
			}))
	}


	// async/await 并发执行异步操作
	//原生async/await的用法
	let app = async () => {
		let p = await Promise.all([wait(500), wait(200), wait(2000)]);
		console.log(p);
	}
	app();

	// async  await语法糖
	let a1 = () => {
		return new Promise((resolve, reject) => {
			setTimeout(() => {
				resolve('我是a1')
			}, 4000)
		})
	}
	let a2 = () => {
		return new Promise((resolve, reject) => {
			setTimeout(() => {
				resolve('我是a2')
			}, 40)
		})
	}
	let a3 = () => {
		return new Promise((resolve, reject) => {
			setTimeout(() => {
				resolve('我是a3')
			}, 40)
		})
	}
	// 想让a1完成后再执行a2再执行a3
	//能避免回调
	async function asy() {
		await a1().then((res) => {
			console.log(res)
		});
		await a2().then((res) => {
			console.log(res)
		});;
		await a3().then((res) => {
			console.log(res)
		});;
	}
	asy();


	/* ================================================ */

	// JS继承的几种方式

	(1) 属性拷贝(就是将对象的成员复制一份给需要继承的对象)
	// 创建父对象
	var superObj = {
		name: 'Li',
		age: 25,
		friends: ['小明', '小李', '小赵'],
		showName: function() {
			alert(this.name);
		}
	}

	// 创建需要继承的子对象
	var subObj = {};

	// 开始拷贝属性(使用for...in...循环)
	for (var i in superObj) {
		subObj[i] = superObj[i];
	}

	console.log(subObj)
	console.log(superObj)
	存在问题：

	如果继承过来的成员是引用类型的话,
	那么这个引用类型的成员在父对象和子对象之间是共享的,
	也就是说修改了之后,
	父子对象都会受到影响.

	2) 原型式继承(借用构造函数的原型对象实现继承)

function Parent() {
	this.name = 'parent';
	this.play = [1, 2, 3];
}

function Child() {
	this.type = 'child';
}
Child.prototype = new Parent();

var s1 = new Child();
var s2 = new Child();
console.log(s1.play, s2.name); //(3) [1, 2, 3] (3) ‘parent’
s1.play.push(4);
console.log(s1.play, s2.play); //(4) [1, 2, 3, 4] (4) [1, 2, 3, 4]
问题：

1. 父构造函数的原型对象和子构造函数的原型对象上的成员有共享问题
2. 只能继承父构造函数的原型对象上的成员, 不能继承父构造函数的实例对象的成员

new => 就是实例化一个函数, 调用函数把返回值赋给变量
prototype => 对象构造器添加新属性
